#!/usr/bin/env python3
"""
数字人视频背景替换系统启动脚本 - Windows兼容版本
自动检查依赖、安装npm包、启动前后端服务
"""

import os
import sys
import subprocess
import time
import webbrowser
import platform
import shutil
from pathlib import Path


class VueSystemStarter:
    def __init__(self):
        self.base_dir = Path(__file__).parent
        self.frontend_dir = self.base_dir / 'frontend'
        self.backend_dir = self.base_dir / 'backend'
        self.npm_cmd = 'npm'  # 默认命令，会在检查时更新
        self.required_backend_dirs = [
            'backend',
            'backend/uploads',
            'backend/outputs',
            'backend/library/human',
            'backend/library/background',
            'backend/temp',
            'backend/previews',
            'backend/static'
        ]

    def check_node_npm(self):
        """检查Node.js和npm - Windows兼容版本"""
        print("🔍 检查Node.js和npm...")

        # 获取当前环境的PATH，并添加常见的Node.js安装路径
        env = os.environ.copy()

        # 添加常见的Node.js安装路径到PATH
        common_paths = []
        if platform.system() == "Windows":
            common_paths = [
                r"C:\Program Files\nodejs",
                r"C:\Program Files (x86)\nodejs",
                os.path.expanduser(r"~\AppData\Roaming\npm"),
            ]
        elif platform.system() == "Darwin":  # macOS
            common_paths = [
                "/usr/local/bin",
                "/opt/homebrew/bin",
                "/usr/local/lib/node_modules/.bin",
            ]
        else:  # Linux
            common_paths = [
                "/usr/local/bin",
                "/usr/bin",
                os.path.expanduser("~/.local/bin"),
            ]

        # 扩展PATH
        current_path = env.get('PATH', '')
        for path in common_paths:
            if os.path.exists(path) and path not in current_path:
                current_path = path + os.pathsep + current_path

        env['PATH'] = current_path

        # 检查node - Windows优先使用node.exe
        node_found = False
        node_commands = ['node.exe', 'node'] if platform.system() == 'Windows' else ['node']

        for cmd in node_commands:
            try:
                result = subprocess.run([cmd, '--version'],
                                        capture_output=True, text=True,
                                        check=True, env=env, timeout=10)
                node_version = result.stdout.strip()
                print(f"✅ Node.js {node_version} 已安装 (使用 {cmd})")
                node_found = True
                break
            except (subprocess.CalledProcessError, FileNotFoundError, subprocess.TimeoutExpired):
                continue

        if not node_found:
            print("❌ Node.js 未找到")
            self._show_node_install_help()
            return False

        # 检查npm - Windows优先使用npm.cmd
        npm_found = False
        npm_commands = ['npm.cmd', 'npm'] if platform.system() == 'Windows' else ['npm']

        for cmd in npm_commands:
            try:
                result = subprocess.run([cmd, '--version'],
                                        capture_output=True, text=True,
                                        check=True, env=env, timeout=10)
                npm_version = result.stdout.strip()
                print(f"✅ npm {npm_version} 已安装 (使用 {cmd})")
                # 保存成功的命令供后续使用
                self.npm_cmd = cmd
                npm_found = True
                break
            except (subprocess.CalledProcessError, FileNotFoundError, subprocess.TimeoutExpired):
                continue

        if not npm_found:
            print("❌ npm 未找到")
            self._show_npm_install_help()
            return False

        return True

    def _show_node_install_help(self):
        """显示Node.js安装帮助"""
        print("\n📥 Node.js 安装建议:")
        if platform.system() == "Windows":
            print("1. 访问 https://nodejs.org/ 下载Windows安装包")
            print("2. 或使用 winget: winget install OpenJS.NodeJS")
            print("3. 或使用 choco: choco install nodejs")
            print("4. 安装后请重启命令提示符")
        elif platform.system() == "Darwin":
            print("1. 访问 https://nodejs.org/ 下载macOS安装包")
            print("2. 或使用 brew: brew install node")
            print("3. 或使用 nvm: curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash")
        else:
            print("1. Ubuntu/Debian: sudo apt-get install nodejs npm")
            print("2. CentOS/RHEL: sudo yum install nodejs npm")
            print("3. 或使用 nvm: curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash")

    def _show_npm_install_help(self):
        """显示npm安装帮助"""
        print("\n📦 npm 通常随Node.js一起安装")
        print("如果npm缺失，可以尝试:")
        print("1. 重新安装Node.js")
        print("2. 重启命令提示符")
        print("3. 检查环境变量PATH是否包含Node.js路径")

    def check_python_version(self):
        """检查Python版本"""
        print("🐍 检查Python版本...")
        if sys.version_info < (3, 7):
            print("❌ 需要Python 3.7或更高版本")
            return False
        print(f"✅ Python {sys.version.split()[0]} 已安装")
        return True

    def check_python_dependencies(self):
        """检查Python依赖"""
        print("📦 检查Python依赖...")
        required_packages = [
            ('flask', 'flask'),
            ('flask_cors', 'flask-cors'),
            ('cv2', 'opencv-python'),
            ('numpy', 'numpy'),
            ('PIL', 'pillow')
        ]

        missing_packages = []
        for import_name, install_name in required_packages:
            try:
                if import_name == 'cv2':
                    import cv2
                elif import_name == 'PIL':
                    import PIL
                else:
                    __import__(import_name)
                print(f"✅ {install_name}")
            except ImportError:
                print(f"❌ {install_name}")
                missing_packages.append(install_name)

        if missing_packages:
            print(f"\n🔧 安装缺失的Python依赖...")
            for package in missing_packages:
                print(f"安装 {package}...")
                try:
                    subprocess.check_call([sys.executable, '-m', 'pip', 'install', package])
                    print(f"✅ {package} 安装成功")
                except subprocess.CalledProcessError:
                    print(f"❌ {package} 安装失败")
                    return False

        return True

    def check_ffmpeg(self):
        """检查FFmpeg"""
        print("🎬 检查FFmpeg...")
        try:
            result = subprocess.run(['ffmpeg', '-version'],
                                    capture_output=True, text=True, check=True)
            print("✅ FFmpeg 已安装")
            return True
        except (subprocess.CalledProcessError, FileNotFoundError):
            print("❌ FFmpeg 未安装")
            print("请安装FFmpeg:")
            print("  Windows: choco install ffmpeg 或下载手动安装")
            print("  macOS: brew install ffmpeg")
            print("  Linux: sudo apt install ffmpeg")
            return False

    def create_directories(self):
        """创建必要的文件夹"""
        print("📁 创建文件夹结构...")

        # 创建后端文件夹
        for dir_path in self.required_backend_dirs:
            full_path = self.base_dir / dir_path
            full_path.mkdir(parents=True, exist_ok=True)
            print(f"✅ {dir_path}")

        # 创建前端文件夹
        self.frontend_dir.mkdir(exist_ok=True)
        print(f"✅ frontend")

    def setup_frontend(self):
        """设置前端项目"""
        print("\n🎨 设置Vue前端项目...")

        # 检查package.json是否存在
        package_json = self.frontend_dir / 'package.json'
        if not package_json.exists():
            print("❌ 前端项目文件不存在")
            print("请确保已将Vue项目文件复制到 frontend/ 文件夹")
            return False

        # 检查node_modules是否存在
        node_modules = self.frontend_dir / 'node_modules'
        if not node_modules.exists():
            print("📦 安装前端依赖...")
            try:
                # 使用国内镜像加速（可选）
                subprocess.run([self.npm_cmd, 'config', 'set', 'registry',
                                'https://registry.npmmirror.com'],
                               cwd=self.frontend_dir, check=True,
                               shell=platform.system() == 'Windows')

                # 安装依赖
                subprocess.run([self.npm_cmd, 'install'],
                               cwd=self.frontend_dir,
                               check=True,
                               shell=platform.system() == 'Windows')
                print("✅ 前端依赖安装成功")
            except subprocess.CalledProcessError as e:
                print(f"❌ 前端依赖安装失败: {e}")
                return False
        else:
            print("✅ 前端依赖已安装")

        return True

    def copy_backend_file(self):
        """复制后端文件"""
        print("\n📄 准备后端文件...")

        # 复制app.py到backend目录
        source_app = self.base_dir / 'app.py'
        target_app = self.backend_dir / 'app.py'

        if source_app.exists() and not target_app.exists():
            shutil.copy2(source_app, target_app)
            print("✅ 已复制 app.py 到 backend/")
        elif target_app.exists():
            print("✅ backend/app.py 已存在")
        else:
            print("⚠️  找不到 app.py 文件")

    def start_backend(self):
        """启动后端服务"""
        print("\n🚀 启动后端服务...")

        app_file = self.backend_dir / 'app.py'

        if not app_file.exists():
            print("❌ 后端应用文件不存在")
            return None

        try:
            # 启动Flask应用
            env = os.environ.copy()
            env['PYTHONPATH'] = str(self.backend_dir)

            process = subprocess.Popen([
                sys.executable, str(app_file)
            ], cwd=self.backend_dir, env=env)

            print("✅ 后端服务启动中... (端口 5001)")
            return process
        except Exception as e:
            print(f"❌ 后端启动失败: {e}")
            return None

    def start_frontend(self):
        """启动前端开发服务器"""
        print("\n🌐 启动前端开发服务器...")

        try:
            # 启动开发服务器
            if platform.system() == 'Windows':
                # Windows下使用shell=True和完整命令
                process = subprocess.Popen(
                    f'{self.npm_cmd} run dev',
                    cwd=self.frontend_dir,
                    shell=True
                )
            else:
                process = subprocess.Popen(
                    [self.npm_cmd, 'run', 'dev'],
                    cwd=self.frontend_dir
                )

            print("✅ 前端开发服务器启动中... (端口 8080)")
            return process
        except Exception as e:
            print(f"❌ 前端启动失败: {e}")
            return None

    def wait_for_services(self):
        """等待服务启动"""
        print("\n⏳ 等待服务启动...")

        # 等待后端服务
        backend_ready = False
        for i in range(30):
            try:
                import urllib.request
                urllib.request.urlopen('http://localhost:5001/api/health', timeout=10)
                print("✅ 后端服务已就绪")
                backend_ready = True
                break
            except:
                time.sleep(1)
                if i % 5 == 0:
                    print(f"等待后端服务... ({i + 1}/30)")

        if not backend_ready:
            print("⚠️  后端服务启动超时")

        # 等待前端服务
        frontend_ready = False
        for i in range(20):
            try:
                import urllib.request
                urllib.request.urlopen('http://localhost:8080', timeout=1)
                print("✅ 前端服务已就绪")
                frontend_ready = True
                break
            except:
                time.sleep(1)
                if i % 3 == 0:
                    print(f"等待前端服务... ({i + 1}/20)")

        if not frontend_ready:
            print("⚠️  前端服务启动超时")

        return backend_ready and frontend_ready

    def open_browser(self):
        """打开浏览器"""
        print("\n🌐 打开浏览器...")
        try:
            webbrowser.open('http://localhost:8080')
            print("✅ 浏览器已打开")
        except Exception as e:
            print(f"⚠️  无法自动打开浏览器: {e}")
            print("请手动访问: http://localhost:8080")

    def show_status(self):
        """显示服务状态"""
        print("\n" + "=" * 60)
        print("🎉 数字人视频背景替换系统已启动!")
        print("=" * 60)
        print("🛑 停止服务: Ctrl+C")
        print()

    def run(self):
        """运行完整的启动流程"""
        print("🚀 数字人视频背景替换系统启动器 (Windows兼容版本)")
        print("=" * 60)

        # 检查环境
        if not self.check_node_npm():
            return False

        if not self.check_python_version():
            return False

        if not self.check_python_dependencies():
            return False

        if not self.check_ffmpeg():
            print("⚠️  FFmpeg未安装，部分功能可能不可用")

        # 准备环境
        self.create_directories()
        self.copy_backend_file()

        # 设置前端
        if not self.setup_frontend():
            return False

        # 启动服务
        backend_process = self.start_backend()
        if not backend_process:
            return False

        time.sleep(3)  # 给后端一点启动时间

        frontend_process = self.start_frontend()
        if not frontend_process:
            backend_process.terminate()
            return False

        # 等待服务就绪
        if self.wait_for_services():
            # 打开浏览器
            self.open_browser()

        # 显示状态信息
        self.show_status()

        # 等待用户中断
        try:
            while True:
                time.sleep(1)
        except KeyboardInterrupt:
            print("\n🛑 正在停止服务...")
            if backend_process:
                backend_process.terminate()
            if frontend_process:
                frontend_process.terminate()
            print("✅ 服务已停止")

        return True


def main():
    """主函数"""
    starter = VueSystemStarter()

    try:
        success = starter.run()
        if not success:
            print("❌ 启动失败")
            print("\n请确保:")
            print("1. 已安装 Node.js (https://nodejs.org/)")
            print("2. 已安装 Python 3.7+")
            print("3. 已安装 FFmpeg")
            print("4. 前端文件已复制到 frontend/ 文件夹")
            print("5. Windows用户请确保使用管理员权限或重启命令提示符")
            sys.exit(1)
    except Exception as e:
        print(f"❌ 启动异常: {e}")
        import traceback
        traceback.print_exc()
        sys.exit(1)


if __name__ == '__main__':
    main()